﻿using System;
using System.Collections.Generic;
using System.Text;
using EquationSolver;

namespace AdaptiveAgents.Tools
{
    public class AgentData
    {
        // agent's epsilon
        public double Epsilon { get; set; }
        // agent's compentance
        public double Competence { get; set; }

        // ctor
        public AgentData(double epsilon, double competence)
        {
            Epsilon = epsilon;
            Competence = competence;
        }
    }

    public class ProbabilityTable : ICloneable
    {
        // table size
        public int Size { get; set; }
        // the table 
        double[,] matrix;

        //ctor
        public ProbabilityTable(int size)
        {
            this.Size = size;
            matrix = new double[size,size]; 
        }

        public Object Clone()
        {
            ProbabilityTable m = new ProbabilityTable(Size);
            for (int i = 0; i < Size; i++)
            {
                for (int j = 0; j < Size; j++)
                {
                    m.matrix[i, j] = matrix[i, j];
                }
            }
            return m;
        }

        //[] operator
        public double this[int i, int j]
        {
            get
            {
                return matrix[i,j];
            }
            set
            {
                matrix[i,j] = value;
            }
        }
    }

    public class AgentGroup
    {
        public List<AgentData> Agents { get; private set; }
        public int BestAgent { get; private set;} 

        public AgentGroup()
        {
            Agents = new List<AgentData>();
        }

        public void Add(AgentData a)
        {
            Agents.Add(a);
        }

        public void GetBestAgent()
        {
            double max = 0;
            for (int i = 0; i < Agents.Count; i++)
            {
                AgentData a = Agents[i];
                if (a.Competence > max)
                {
                    max = a.Competence;
                    BestAgent = i;
                }
            }  
        }
        

        public ProbabilityTable CreateProbabilityTable()
        {
            GetBestAgent();
            ProbabilityTable m = new ProbabilityTable(Agents.Count);

            for (int i = 0; i < Agents.Count; i++)
            {

                for (int j = 0; j < Agents.Count; j++)
                {
                    m[i, j] = calcP(i, j);
                }
            }

            // check
            //for (int i = 0; i < agents.Count; i++)
            //{
            //    double sum = 0;
            //    for (int j = 0; j < agents.Count; j++)
            //    {
            //        sum += m[i, j];
            //    }

            //    Console.Write(sum);
            //}

           return m;
        }

        private double calcP(int i, int j)
        {
            AgentData ai = Agents[i];
            AgentData aj = Agents[j];

            double regularP = ai.Epsilon / (double)(Agents.Count - 1);
            double bestP = 1 - ai.Epsilon;

            double val = 0;
            // i == best
            if (i == BestAgent)
            {
                if (j == BestAgent)
                {
                    val = bestP;
                }
                else
                {
                    val = regularP;
                }
            }

            else
            {
                if (j == BestAgent)
                {
                    val = bestP + regularP;
                }
                else if(i == j)
                {
                    val = 0;
                }
                else
                {
                    val = regularP;
                }
            }
           
            return val;
        }


        public double Solve(ProbabilityTable table)
        {
            EquationSolver.EquationSolver es = new EquationSolver.EquationSolver();
            List<double[]> equations = new List<double[]>();
            List<double[]> solutions = new List<double[]>();

            double[] first = new double[table.Size + 1];
            for (int i = 0; i < table.Size + 1; i++)
            {
                first[i] = 1;
            }

           
            for (int j = 0; j < table.Size; j++)
            {
                double[] eq = new double[table.Size + 1];

                for (int i = 0; i < table.Size; i++)
                {
                    eq[i] = table[i, j];
                    if (i == j)
                    {
                        eq[i] -= 1;
                    }
                }
                eq[table.Size] = 0;
                equations.Add(eq);
            }



            //for (int i = 0; i < table.Size; i++)
            //{
            int exclude = Generator.getNextInt(equations.Count);

            es.addEquation((double[])first.Clone());

            for (int j = 0; j < equations.Count; j++)
            {
                if (exclude == j)
                { continue; }
               es.addEquation((double[])equations[j].Clone());
            }
            solutions.Add(es.solve());
            es.clear();
            //}

           
            //foreach(double[] sol in solutions)
            //{
            //    double sum = 0;
            //    for (int i = 0; i < sol.Length; i++)
            //    {
            //        sum += sol[i];
            //    }
            //    if (Math.Abs(sum - 1)> 0.00001) throw new Exception("not equal");
            //}


            double result = 0;
            double[] solution = solutions[0];
            for (int i = 0; i < solution.Length; i++)
            {
                result += Agents[i].Competence * solution[i];
            }

            return result;
 
        }

        
    }
}
